#include "CRegionSceneNode.h"

ITexture* getColorTexture(IVideoDriver *video, const SColor color)
{
	stringc name = stringc("color_") + stringc(color.getAlpha()) + stringc(color.getRed()) + stringc(color.getGreen()) + stringc(color.getBlue());
	ITexture * a = video->getTexture(name);
	if(a)
		return a;
	IImage *b = video->createImage(video::ECF_A8R8G8B8, dimension2d<u32>(1,1));
	b->setPixel(0,0, color);
	a = video->addTexture(name, b);
	return a;
}

SColor colorFromMatGloss(DFHack::t_matgloss matgloss)
{
	int a = matgloss.fore;
	if(matgloss.bright)
		a += 8;
	switch(a)
	{
	case 0:
		return SColor(255, 0, 0, 0);
	case 1:
		return SColor(255, 0, 0, 128);
	case 2:
		return SColor(255, 0, 128, 0);
	case 3:
		return SColor(255, 0, 128, 128);
	case 4:
		return SColor(255, 128, 0, 0);
	case 5:
		return SColor(255, 128, 0, 128);
	case 6:
		return SColor(255, 128, 128, 0);
	case 7:
		return SColor(255, 192, 192, 192);
	case 8:
		return SColor(255, 128, 128, 128);
	case 9:
		return SColor(255, 0, 0, 255);
	case 10:
		return SColor(255, 0, 255, 0);
	case 11:
		return SColor(255, 0, 255, 255);
	case 12:
		return SColor(255, 255, 0, 0);
	case 13:
		return SColor(255, 255, 0, 255);
	case 14:
		return SColor(255, 255, 255, 0);
	case 15:
		return SColor(255, 255, 255, 255);
	}
	return SColor(255, 255, 255, 255);
}

SColor colorFromMatGloss(u32 f, u32 b, u32 g)
{
	DFHack::t_matgloss m;
	m.fore = f;
	m.back = b;
	m.bright = g;
	return colorFromMatGloss(m);
}

CRegionSceneNode::CRegionSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, vector3di size,
				const core::vector3df& position,
				const core::vector3df& rotation,
				const core::vector3df& scale)
				: ISceneNode(parent, mgr, id, position, rotation, scale),
				Size(size), ForceRecalculation(false), CameraMovementDelta(1.0f), CameraRotationDelta(1.0f), CameraFOVDelta(0.1f),
				CurrentBlock(0), CurrentPosition(vector3df(0,0,0)), Wireframe(false), ShowTerrain(true), DrawDistance(200.0f), Hq(false),
				MaxUp(9999999.0f), MaxDown(999999.0f),
				UseBatching(true)
{
	this->setTriangleSelector(mgr->createMetaTriangleSelector());

	//setPosition(vector3df(Size.X*16,0,0));

	BlockMesh = SceneManager->getGeometryCreator()->createCubeMesh(vector3df(1,1,1));

	SMaterial mat;
	addResource(new SResource("FLOOR", DFHack::FLOOR, DFHack::PEBBLES, SceneManager->getMesh("data/meshes/floor.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/floor.png")*//*, mat*/));

//	addResource(new SResource("WALL", DFHack::WALL, DFHack::FORTIFICATION, SceneManager->getMesh("data/meshes/wall.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/wall.png")*//*, mat*/));
	
//	addResource(new SResource("WALL1_ROUGH_SOUTH_WEST", SceneManager->getMesh("data/meshes/wall1_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(0,0,0), vector3df(0,0,0)));
//	addResource(new SResource("WALL1_ROUGH_NORTH_WEST", SceneManager->getMesh("data/meshes/wall1_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(0,0,1), vector3df(0,90,0)));
//	addResource(new SResource("WALL1_ROUGH_SOUTH_EAST", SceneManager->getMesh("data/meshes/wall1_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(1,0,0), vector3df(0,270,0)));
//	addResource(new SResource("WALL1_ROUGH_NORTH_EAST", SceneManager->getMesh("data/meshes/wall1_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(1,0,1), vector3df(0,180,0)));

//	addResource(new SResource("WALL2_ROUGH_SOUTH", SceneManager->getMesh("data/meshes/wall2_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(0,0,0), vector3df(0,0,0)));
//	addResource(new SResource("WALL2_ROUGH_NORTH", SceneManager->getMesh("data/meshes/wall2_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(1,0,1), vector3df(0,180,0)));
//	addResource(new SResource("WALL2_ROUGH_WEST", SceneManager->getMesh("data/meshes/wall2_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(0,0,1), vector3df(0,90,0)));
//	addResource(new SResource("WALL2_ROUGH_EAST", SceneManager->getMesh("data/meshes/wall2_rough.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*/, vector3df(1,0,0), vector3df(0,270,0)));

//	addResource(new SResource("RAMP", DFHack::RAMP, SceneManager->getMesh("data/meshes/wall.obj"), 0/*SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")*//*, mat*/));

//	addResource(new SResource("STAIR_UPDOWN", DFHack::STAIR_UPDOWN, SceneManager->getMesh("data/meshes/stair_updown.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/stair.png")/*, mat*/));
//	addResource(new SResource("STAIR_UP", DFHack::STAIR_UP, SceneManager->getMesh("data/meshes/stair_up.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/stair.png")/*, mat*/));
//	addResource(new SResource("STAIR_DOWN", DFHack::STAIR_DOWN, 0, 0/*, mat*/));

/*	addResource(new SResource("RAMP1", SceneManager->getMesh("data/meshes/ramp1.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")));
	addResource(new SResource("RAMP2", SceneManager->getMesh("data/meshes/ramp2.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png")));

	addResource(new SResource("RAMP4D", SceneManager->getMesh("data/meshes/ramp4d.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));

	addResource(new SResource("RAMP4_WEST", SceneManager->getMesh("data/meshes/ramp4.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP4_EAST", SceneManager->getMesh("data/meshes/ramp4.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP4_NORTH", SceneManager->getMesh("data/meshes/ramp4.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP4_SOUTH", SceneManager->getMesh("data/meshes/ramp4.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));

	addResource(new SResource("RAMP4A_SOUTH_WEST", SceneManager->getMesh("data/meshes/ramp4a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP4A_SOUTH_EAST", SceneManager->getMesh("data/meshes/ramp4a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP4A_NORTH_EAST", SceneManager->getMesh("data/meshes/ramp4a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP4A_NORTH_WEST", SceneManager->getMesh("data/meshes/ramp4a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));

	addResource(new SResource("RAMP4B_NORTH_SOUTH", SceneManager->getMesh("data/meshes/ramp4b.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP4B_EAST_WEST", SceneManager->getMesh("data/meshes/ramp4b.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));

	addResource(new SResource("RAMP4C_WEST", SceneManager->getMesh("data/meshes/ramp4c.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP4C_EAST", SceneManager->getMesh("data/meshes/ramp4c.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,1,0), vector3df(0,180,0)));
	addResource(new SResource("RAMP4C_NORTH", SceneManager->getMesh("data/meshes/ramp4c.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP4C_SOUTH", SceneManager->getMesh("data/meshes/ramp4c.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,1,0), vector3df(0,270,0)));

	addResource(new SResource("RAMP3B_SOUTH_WEST", SceneManager->getMesh("data/meshes/ramp3b.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));

	addResource(new SResource("RAMP3A_EAST", SceneManager->getMesh("data/meshes/ramp3a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP3A_SOUTH_WEST", SceneManager->getMesh("data/meshes/ramp3a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP3A_SOUTH_WEST_FLIPZ", SceneManager->getMesh("data/meshes/ramp3a_flipz.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP3A_SOUTH_EAST", SceneManager->getMesh("data/meshes/ramp3a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP3A_NORTH_WEST_FLIPZ", SceneManager->getMesh("data/meshes/ramp3a_flipz.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP3A_NORTH_WEST", SceneManager->getMesh("data/meshes/ramp3a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP3A_NORTH_EAST", SceneManager->getMesh("data/meshes/ramp3a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP3A_NORTH_EAST_FLIPZ", SceneManager->getMesh("data/meshes/ramp3a_flipz.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP3A_SOUTH_EAST_FLIPZ", SceneManager->getMesh("data/meshes/ramp3a_flipz.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP3A_SOUTH", SceneManager->getMesh("data/meshes/ramp3a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));

	addResource(new SResource("RAMP3_SOUTH_WEST", SceneManager->getMesh("data/meshes/ramp3.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP3_NORTH_WEST", SceneManager->getMesh("data/meshes/ramp3.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP3_SOUTH_EAST", SceneManager->getMesh("data/meshes/ramp3.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP3_NORTH_EAST", SceneManager->getMesh("data/meshes/ramp3.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"),  vector3df(1,0,1), vector3df(0,180,0)));

	addResource(new SResource("RAMP2_WEST", SceneManager->getMesh("data/meshes/ramp2.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP2_EAST", SceneManager->getMesh("data/meshes/ramp2.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP2_NORTH", SceneManager->getMesh("data/meshes/ramp2.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP2_SOUTH", SceneManager->getMesh("data/meshes/ramp2.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));

	addResource(new SResource("RAMP2A_WEST", SceneManager->getMesh("data/meshes/ramp2a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP2A_EAST", SceneManager->getMesh("data/meshes/ramp2a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));
	addResource(new SResource("RAMP2A_NORTH", SceneManager->getMesh("data/meshes/ramp2a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP2A_SOUTH", SceneManager->getMesh("data/meshes/ramp2a.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));

	addResource(new SResource("RAMP2B_NORTH_WEST_SOUTH_EAST", SceneManager->getMesh("data/meshes/ramp2b.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP2B_NORTH_EAST_SOUTH_WEST", SceneManager->getMesh("data/meshes/ramp2b.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));

	addResource(new SResource("RAMP1_SOUTH_EAST", SceneManager->getMesh("data/meshes/ramp1.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,0), vector3df(0,0,0)));
	addResource(new SResource("RAMP1_NORTH_WEST", SceneManager->getMesh("data/meshes/ramp1.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,1), vector3df(0,180,0)));
	addResource(new SResource("RAMP1_SOUTH_WEST", SceneManager->getMesh("data/meshes/ramp1.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(0,0,1), vector3df(0,90,0)));
	addResource(new SResource("RAMP1_NORTH_EAST", SceneManager->getMesh("data/meshes/ramp1.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/ramp.png"), vector3df(1,0,0), vector3df(0,270,0)));

	addResource(new SResource("door", SceneManager->getMesh("data/meshes/door.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/door.png")));
	addResource(new SResource("bed", SceneManager->getMesh("data/meshes/bed.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/stone.png")));
	addResource(new SResource("cabinet", SceneManager->getMesh("data/meshes/cabinet.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/stone.png")));
	addResource(new SResource("throne", SceneManager->getMesh("data/meshes/throne.obj"), SceneManager->getVideoDriver()->getTexture("data/textures/stone.png")));
	
	IImage *img = mgr->getVideoDriver()->createImage(video::ECF_A8R8G8B8, dimension2d<u32>(1,1));
	img->setPixel(0,0, SColor(16, 0, 0, 255));
	ITexture *dt = mgr->getVideoDriver()->addTexture("default", img);
	*/
	DummyNode = new CPickSceneNode(0, mgr, -1, vector3df((f32)Size.X * 16, (f32)Size.Y, (f32)Size.Z * 16));

	BoundingBox = aabbox3d<f32>(position.X, position.Y, position.Z, position.X + Size.X * 16, position.Y + Size.Y, position.Z + Size.Z * 16);

	VisibleBlocks = 0;
	BlockCount = Size.X * Size.Y * Size.Z;
	Blocks = new CBlockSceneNode*[BlockCount];

	CBlockCollection *bc = 0;

	for(s32 x = 0; x < Size.X; x++)
	{
	//	for(s32 y = 0; y < Size.Y; y++)
		for(s32 z = 0; z < Size.Z; z++)
		{
//			for(s32 z = 0; z < Size.Z; z++)
			for(s32 y = 0; y < Size.Y; y++)
			{
				if(y % 4 == 0)
				{
					bc = new CBlockCollection();
					BlockCollections.push_back(bc);
				}

//				u32 index = z * Size.Y * Size.X + y * Size.X + x;
				u32 index = z * Size.Y * Size.X + y * Size.X + (Size.X - x - 1);
				Blocks[index] = new CBlockSceneNode(0, SceneManager, 2, this, vector3di(Size.X - x - 1, y, z), vector3df(	(-((f32)x * 16)) + Size.X * 16 - 16, (f32)y, (f32)z * 16), vector3df(0,0,0), vector3df(1,1,1));
				DummyNode->addChild((ISceneNode*)Blocks[index]);
				Blocks[index]->drop();
			//	Blocks[z * Size.Y * Size.X + y * Size.X + x]->setAutomaticCulling(scene::E_CULLING_TYPE.EAC_FRUSTUM_BOX);

				bc->addBlock(Blocks[index]);
			//	BoundingBox.addInternalBox(Blocks[z * Size.Y * Size.X + y * Size.X + x]->getBoundingBox());
			}
		}
	}

	/*IMesh *watermesh = SceneManager->addHillPlaneMesh("water", dimension2d<f32>(0.25, 0.25), dimension2d<u32>(100, 100), 0, 0, dimension2d<f32>(0, 0), dimension2d<f32>(10, 10));
	ISceneNode *node = SceneManager->addWaterSurfaceSceneNode(watermesh, 0.1f, 0.0001f, 1, 0, -1, vector3df(0,0,0), vector3df(0,0,0), vector3df(10, 10, 10));

	node->setMaterialTexture(0, SceneManager->getVideoDriver()->getTexture("data/textures/stones.jpg"));
    node->setMaterialTexture(1, SceneManager->getVideoDriver()->getTexture("data/textures/water.jpg"));

    node->setMaterialType(video::EMT_REFLECTION_2_LAYER);*/
}

CRegionSceneNode::~CRegionSceneNode()
{
	u32 c = BlockCount;
	for(u32 i = 0; i < c; i++)
		if(Blocks[i])
			delete Blocks[i];
	Blocks = 0;

	c = Resources.size();
	for(u32 i = 0; i < c; i++)
		delete Resources[i];
	Resources.clear();

	c = InorganicMaterials.size();
	for(u32 i = 0; i < c; i++)
		delete InorganicMaterials[i];
	InorganicMaterials.clear();

	c = OrganicMaterials.size();
	for(u32 i = 0; i < c; i++)
		delete OrganicMaterials[i];
	OrganicMaterials.clear();

	c = WoodMaterials.size();
	for(u32 i = 0; i < c; i++)
		delete WoodMaterials[i];
	WoodMaterials.clear();

	c = PlantMaterials.size();
	for(u32 i = 0; i < c; i++)
		delete PlantMaterials[i];
	PlantMaterials.clear();

	c = OtherMaterials.size();
	for(u32 i = 0; i < c; i++)
		delete OtherMaterials[i];
	OtherMaterials.clear();

	c = BlockCollections.size();
	for(u32 i = 0; i < c; i++)
		delete BlockCollections[i];
	BlockCollections.clear();

	for(u32 i = 0; i < ShaderMaterials.size(); i++)
		delete ShaderMaterials[i];

	//ISceneNode::~ISceneNode();
}

void CRegionSceneNode::preRender()
{
	ICameraSceneNode * camera = SceneManager->getActiveCamera();
	if(!camera)
		return;

	SceneManager->registerNodeForRendering(this);

	const vector3df cameraPosition = camera->getAbsolutePosition();
	const vector3df cameraRotation = line3d<f32>(cameraPosition, camera->getTarget()).getVector().getHorizontalAngle();
	vector3df cameraUp = camera->getUpVector();
	cameraUp.normalize();
	const f32 CameraFOV = SceneManager->getActiveCamera()->getFOV();

	// Only check on the Camera's Y Rotation
	if (!ForceRecalculation)
	{
		if ((fabsf(cameraRotation.X - OldCameraRotation.X) < CameraRotationDelta) &&
			(fabsf(cameraRotation.Y - OldCameraRotation.Y) < CameraRotationDelta))
		{
			if ((fabs(cameraPosition.X - OldCameraPosition.X) < CameraMovementDelta) &&
				(fabs(cameraPosition.Y - OldCameraPosition.Y) < CameraMovementDelta) &&
				(fabs(cameraPosition.Z - OldCameraPosition.Z) < CameraMovementDelta))
			{
				if (fabs(CameraFOV-OldCameraFOV) < CameraFOVDelta &&
					cameraUp.dotProduct(OldCameraUp) > (1.f - (cos(core::DEGTORAD * CameraRotationDelta))))
				{
					return;
				}
			}
		}
	}

	/*if(CurrentBlock == 0)
	{
		CurrentBlock = getBlock(CurrentPosition);
		if(CurrentBlock != 0)
		{
			SBlocks blocks = getSurroundingBlocks(CurrentPosition);
			for(u32 i = 0; i < 9; i++)
				if(blocks.Blocks[i] != 0)
				{
					//printf("%f, %f, %f\n", );
//					BlocksToRender.push_back(blocks.Blocks[i]);
					BlocksToRender.push_back(i);
				}
		}
	}*/

	BlocksToRender.clear();
	((IMetaTriangleSelector*)this->getTriangleSelector())->removeAllTriangleSelectors();

	VisibleBlocks = 0;

	OldCameraPosition = cameraPosition;
	OldCameraRotation = cameraRotation;
	OldCameraUp = cameraUp;
	OldCameraFOV = CameraFOV;

	const SViewFrustum* frustum = SceneManager->getActiveCamera()->getViewFrustum();

	u32 c = BlockCollections.size();
	for(u32 i = 0; i < c; i++)
	{
		BlockCollections[i]->Visible = false;
		aabbox3df box = BlockCollections[i]->getBoundingBox();
		if(frustum->getBoundingBox().intersectsWithBox(box))
		{
		//	const f32 distance = cameraPosition.getDistanceFromSQ(box.getCenter());

		//	if(distance < DrawDistance * 5)
			{
				BlockCollections[i]->Visible = true;
				BlockCollections[i]->updateTiles();

				if(abs(cameraPosition.getDistanceFromSQ(box.getCenter())) < 200)
				{
					array<CBlockSceneNode*> blocks;
					BlockCollections[i]->getBlocks(blocks);
					u32 c2 = blocks.size();
					for(u32 i2 = 0; i2 < c2; i2++)
					{
			//			if(abs(blocks[i2]->getTransformedBoundingBox().getCenter().Y - cameraPosition.Y) < 1.5f)
				//		{
							((IMetaTriangleSelector*)this->getTriangleSelector())->addTriangleSelector(blocks[i2]->getTriangleSelector());
					//	}
					}
				}

	/*			if(abs(box.getCenter().Y - cameraPosition.Y) < 2.5f && distance < 200.0f)//DrawDistance)
				{
					array<CBlockSceneNode*> blocks;
					BlockCollections[i]->updateTiles();
					BlockCollections[i]->getBlocks(blocks);
					u32 c2 = blocks.size();
					for(u32 i2 = 0; i2 < c2; i2++)
					{
						if(abs(blocks[i2]->getTransformedBoundingBox().getCenter().Y - cameraPosition.Y) < 1.5f)
						{
							//blocks[i2]->optimizeCollisionData();
							((IMetaTriangleSelector*)this->getTriangleSelector())->addTriangleSelector(blocks[i2]->getTriangleSelector());
						}
					}
				}*/
			}
		}
	}

/*	for(u32 i = 0; i < BlockCount; i++)
	{
		CBlockSceneNode *block = Blocks[i];
		if(block != 0 && block->isVisible())
		{
			aabbox3df box = block->getTransformedBoundingBox();
			if(frustum->getBoundingBox().intersectsWithBox(box))
			{*/
				/*const f32 distance = (cameraPosition.X - box.getCenter().X) * (cameraPosition.X - box.getCenter().X) +
					(cameraPosition.Y - box.getCenter().Y) * (cameraPosition.Y - box.getCenter().Y) +
					(cameraPosition.Z - box.getCenter().Z) * (cameraPosition.Z - box.getCenter().Z);*/
	/*			const f32 distance = cameraPosition.getDistanceFromSQ(box.getCenter());

				if(distance < DrawDistance)
				{
					BlocksToRender.push_back(block);
					if(abs(box.getCenter().Y - cameraPosition.Y) < 2.0f && distance < 150.0f)
					{
						block->optimizeCollisionData();
						((IMetaTriangleSelector*)this->getTriangleSelector())->addTriangleSelector(block->getTriangleSelector());
					}
				}
			}
		}
	}*/




	/*s32 tc = TriangleSelector->getTriangleCount();
	if(tc > 0)
	{
		TriangleVertices.set_used(tc * 3);
		TriangleIndices.set_used(tc * 3);
		triangle3df *tr = new triangle3df[tc];
		this->getTriangleSelector()->getTriangles(tr, tc, tc);
		for(s32 i = 0; i < tc; i++)
		{
			TriangleVertices[i * 3] = S3DVertex(tr[i].pointA, vector3df(0,0,0), SColor(255,255,255,255), vector2df(0,0));
			TriangleVertices[i * 3 + 1] = S3DVertex(tr[i].pointB, vector3df(0,0,0), SColor(255,255,255,255), vector2df(0,0));
			TriangleVertices[i * 3 + 2] = S3DVertex(tr[i].pointC, vector3df(0,0,0), SColor(255,255,255,255), vector2df(0,0));
			TriangleIndices[i * 3] = i * 3;
			TriangleIndices[i * 3 + 1] = i * 3 + 1;
			TriangleIndices[i * 3 + 2] = i * 3 + 2;
		}
	}*/
}

void CRegionSceneNode::render()
{
	if(!ShowTerrain) return;
	video::IVideoDriver *video = SceneManager->getVideoDriver();

	u32 c = BlockCollections.size();
	for(u32 i = 0; i < c; i++)
		if(BlockCollections[i]->Visible)
			BlockCollections[i]->render(UseBatching);
	
	/*if(Hq)
	{
		for(u32 i = 0; i < BlockCount; i++)
		{
			CBlockSceneNode *block = Blocks[i];
			block->render();
		}
	}
	else*/
/*	{
		u32 c = BlocksToRender.size();
		for(u32 i = 0; i < c; i++)
		{
			CBlockSceneNode *block = BlocksToRender[i];
			block->render();
		}
	}*/
}

void CRegionSceneNode::removeTile(u32 i)
{
	//	z * Size.Y * Size.X + y * Size.X + x = i
	//printf("%d, %d, %d\n", i % Size.Y, i / Size.Y % Size.X, i / Size.Y / Size.X);
}

CBlockSceneNode* CRegionSceneNode::getBlock(s32 x, s32 y, s32 z) const
{
	if(x >= Size.X || y >= Size.Y || z >= Size.Z || x < 0 || y < 0 || z < 0) return 0;
//	if(x * y * z >= BlockCount) return 0;
	u32 index = z * Size.Y * Size.X + y * Size.X + (Size.X - x - 1);
	return Blocks[index];
	//return Blocks[z * Size.Y * Size.X + y * Size.X + x];
}

CBlockSceneNode* CRegionSceneNode::getBlock(vector3df pos) const
{
	return getBlock((u32)pos.X, (u32)pos.Y, (u32)pos.Z);
}

SBlocks CRegionSceneNode::getSurroundingBlocks(vector3df pos)
{
	SBlocks blocks;
	for(u32 i = 0; i < 9; i++)
		blocks.Blocks[i] = 0;

	blocks.Blocks[0] = getBlock(pos);
	if(pos.X > 0)
		blocks.Blocks[1] = getBlock(pos + vector3df(-1,0,0));
	if(pos.X+1 < Size.X)
		blocks.Blocks[2] = getBlock(pos + vector3df(1,0,0));
	if(pos.Z > 0)
		blocks.Blocks[3] = getBlock(pos + vector3df(0,0,-1));
	if(pos.Z+1 < Size.Z)
		blocks.Blocks[4] = getBlock(pos + vector3df(0,0,1));

	if(pos.X > 0 && pos.Z > 0)
		blocks.Blocks[5] = getBlock(pos + vector3df(-1,0,-1));
	if(pos.X > 0 && pos.Z+1 < Size.Z)
		blocks.Blocks[6] = getBlock(pos + vector3df(-1,0,1));
	if(pos.X+1 < Size.X && pos.Z+1 < Size.Z)
		blocks.Blocks[7] = getBlock(pos + vector3df(1,0,1));
	if(pos.X+1 < Size.X && pos.Z > 0)
		blocks.Blocks[8] = getBlock(pos + vector3df(1,0,-1));
	return blocks;
}

void CRegionSceneNode::removeBlock(ISceneNode *block)
{
}

void CRegionSceneNode::addResource(SResource *resource)
{
	printf("Dfize: Added resource %s\n", resource->Name.c_str());
	Resources.push_back(resource);
}

SResource* CRegionSceneNode::getResource(u16 tiletype) const
{
	if(tiletype >= 520) return 0;
	u32 c = Resources.size();
	for(u32 i = 0; i < c; i++)
	{
		SResource *r = Resources[i];
		if(DFHack::tileTypeTable[tiletype].c >= r->TileTypeMin && DFHack::tileTypeTable[tiletype].c <= r->TileTypeMax)
			return r;
	}
	return 0;
}

SResource* CRegionSceneNode::getResource(std::string name) const
{
	u32 c = Resources.size();
	for(u32 i = 0; i < c; i++)
	{
		if(stricmp(Resources[i]->Name.c_str(), name.c_str()) == 0)
			return Resources[i];
	}
	return 0;
}

array<CBlockSceneNode*> CRegionSceneNode::getBlocksFromLine(line3df line, bool sort)
{
	//std::vector<CBlockSceneNode*> ret;
	array<CBlockSceneNode*> ret;
	std::map<f32,CBlockSceneNode*> blocks;

	u32 c = BlocksToRender.size();
	for(u32 i = 0; i < c; i++)
	{
		CBlockSceneNode *block = BlocksToRender[i];
	/*std::vector<u32>::iterator it = BlocksToRender.begin();
	for(; it != BlocksToRender.end(); ++it)
	{
		CBlockSceneNode *block = Blocks[*it];*/
		if(block != 0 && block->isVisible())
		{
			if(block->getTransformedBoundingBox().intersectsWithLine(line))
			{
				f32 len = line3df(block->getTransformedBoundingBox().getCenter(), line.start).getLength();
				blocks[len] = block;
			}
		}
	}
	std::map<f32,CBlockSceneNode*>::iterator it2 = blocks.begin();
	for(; it2 != blocks.end(); it2++)
		ret.push_back(it2->second);
	return ret;
}

CTile* CRegionSceneNode::getTileFromLine(line3df line)
{
	array<CBlockSceneNode*> blocks = getBlocksFromLine(line);
	u32 c = blocks.size();
	for(u32 i = 0; i < c; i++)
	//std::vector<CBlockSceneNode*>::iterator it = blocks.begin();
//	for(; it != blocks.end(); ++it)
	{
	//	CBlockSceneNode *block = *it;
		CBlockSceneNode *block = blocks[i];
		if(block)
		{
			CTile *tile = block->getTileFromLine(line);
			if(tile != 0)
				return tile;
		}
	}
	return 0;
}

CTile* CRegionSceneNode::getTile(vector3di p) const
{
//	printf("%d, %d, %d\n", Size.X - (p.X / 16) - 1, p.Y, p.Z / 16);
	CBlockSceneNode *block = getBlock(Size.X - (p.X / 16) - 1, p.Y, p.Z / 16);
	return block ? block->getTile((p.X % 16), p.Z % 16) : 0;
}

CTile* CRegionSceneNode::getTile(u32 gx, u32 gy, u32 gz) const
{
	return getTile(vector3di(gx, gy, gz));
}

void CRegionSceneNode::updateTiles()
{
}


// Inorganic
SBasicMaterial* CRegionSceneNode::getInorganicMaterial(u32 index) const
{
	u32 c = InorganicMaterials.size();
	for(u32 i = 0; i < c; i++)
		if(InorganicMaterials[i]->Index == index)
			return InorganicMaterials[i];
	return 0;
}

void CRegionSceneNode::AddInorganicMaterial(SBasicMaterial *m)
{
	InorganicMaterials.push_back(m);
}


// Organic
SBasicMaterial* CRegionSceneNode::getOrganicMaterial(u32 index) const
{
	u32 c = OrganicMaterials.size();
	for(u32 i = 0; i < c; i++)
		if(OrganicMaterials[i]->Index == index)
			return OrganicMaterials[i];
	return 0;
}

void CRegionSceneNode::AddOrganicMaterial(SBasicMaterial *m)
{
	OrganicMaterials.push_back(m);
}


// Other
SBasicMaterial* CRegionSceneNode::getOtherMaterial(u32 index) const
{
	u32 c = OtherMaterials.size();
	for(u32 i = 0; i < c; i++)
		if(OtherMaterials[i]->Index == index)
			return OtherMaterials[i];
	return 0;
}

void CRegionSceneNode::AddOtherMaterial(SBasicMaterial *m)
{
	OtherMaterials.push_back(m);
}


// Plant
SBasicMaterial* CRegionSceneNode::getPlantMaterial(u32 index) const
{
	u32 c = PlantMaterials.size();
	for(u32 i = 0; i < c; i++)
		if(PlantMaterials[i]->Index == index)
			return PlantMaterials[i];
	return 0;
}

void CRegionSceneNode::AddPlantMaterial(SBasicMaterial *m)
{
	PlantMaterials.push_back(m);
}


// Wood
SBasicMaterial* CRegionSceneNode::getWoodMaterial(u32 index) const
{
	u32 c = WoodMaterials.size();
	for(u32 i = 0; i < c; i++)
		if(WoodMaterials[i]->Index == index)
			return WoodMaterials[i];
	return 0;
}

void CRegionSceneNode::AddWoodMaterial(SBasicMaterial *m)
{
	WoodMaterials.push_back(m);
}

u32 CRegionSceneNode::getHiddenTileCount() const
{
	u32 t = 0;
	u32 c = BlockCount;
	for(u32 i = 0; i < c; i++)
		t += Blocks[i]->getHiddenTileCount();
	return t;
}

u32 CRegionSceneNode::getTileCount() const
{
	u32 t = 0;
	u32 c = BlockCount;
	for(u32 i = 0; i < c; i++)
		t += Blocks[i]->getTileCount();
	return t;
}

u32 CRegionSceneNode::getCurrentHiddenTileCount() const
{
	u32 t = 0;
	u32 c = BlockCollections.size();
	for(u32 i = 0; i < c; i++)
	{
		if(BlockCollections[i]->Visible)
		{
			array<CBlockSceneNode*> blocks;
			BlockCollections[i]->getBlocks(blocks);
			for(u32 i2 = 0; i2 < blocks.size(); i2++)
				t += blocks[i2]->getHiddenTileCount();
		}
	}
//	u32 c = BlocksToRender.size();
//	for(u32 i = 0; i < c; i++)
//		t += BlocksToRender[i]->getHiddenTileCount();
	return t;
}

u32 CRegionSceneNode::getCurrentTotalTileCount() const
{
	u32 t = 0;
	u32 c = BlockCollections.size();
	for(u32 i = 0; i < c; i++)
	{
		if(BlockCollections[i]->Visible)
		{
			array<CBlockSceneNode*> blocks;
			BlockCollections[i]->getBlocks(blocks);
			for(u32 i2 = 0; i2 < blocks.size(); i2++)
				t += blocks[i2]->getTileCount();
		}
	}
//	u32 c = BlocksToRender.size();
//	for(u32 i = 0; i < c; i++)
//		t += BlocksToRender[i]->getTileCount();
	return t;
}

CBlockCollection* CRegionSceneNode::getBlockCollection(u32 i)
{
	return BlockCollections[i];
}

SMaterial CRegionSceneNode::readMaterial(std::string name)
{
	CSettings *settings = new CSettings("data/materials/" + name + ".txt", this, "data/materials/default.txt");
	SMaterial m = settings->readMaterial(name, SceneManager->getVideoDriver());
	delete settings;
	return m;
}

SShader* CRegionSceneNode::getShaderMaterial(std::string name) const
{
	for(u32 i = 0; i < ShaderMaterials.size(); i++)
		if(stringc(name.c_str()).equals_ignore_case(ShaderMaterials[i]->Name.c_str()))
			return ShaderMaterials[i];
	return 0;
}

void CRegionSceneNode::addShaderMaterial(std::string name, u32 materialtype)
{
	printf("DFize: Added shader %s(%d)\n", name.c_str(), materialtype);
	ShaderMaterials.push_back(new SShader(name, materialtype));
}

SBasicMaterial* CRegionSceneNode::getMaterial(u32 index, u32 type) const
{
	switch(type)
	{
		// Inorganic
	case 0:
		if(index < InorganicMaterials.size())
			return InorganicMaterials[index];
		break;
		// Wood
	case 420:
		if(index < WoodMaterials.size())
			return WoodMaterials[index];
		break;
	}
	return 0;
}